﻿using System;
using System.Collections;
using System.Collections.Generic;
using DimensionsHelper.Common.Contracts.Metadata;

namespace DimensionsHelper.Services.Metadata;

public class Styles : MetadataObject, IStyles
{
    private readonly Dictionary<string, int> _contextToIndex;

    private readonly List<Style> _styles;


    internal Styles(IMetadataDocument document, IMetadataLabeledObject parent)
        : base(document, ObjectType.Style)
    {
        Parent = parent;
        _styles = [];
        _contextToIndex = new Dictionary<string, int>();
    }


    public Style this[int index] => _styles[index];


    public int Count => _styles.Count;


    public Style? Get(string context)
    {
        return _contextToIndex.TryGetValue(context.ToLower(), out var index) ? _styles[index] : null;
    }


    public Style GetOrAdd(string context)
    {
        var lower = context.ToLower();

        if (_contextToIndex.TryGetValue(lower, out var index))
        {
            return _styles[index];
        }

        _contextToIndex.Add(lower, _styles.Count);
        var newStyle = new Style { Context = context };
        _styles.Add(newStyle);
        return newStyle;
    }


    public void Set(string context, Style style)
    {
        style.Context = context;
        var lower = context.ToLower();

        if (!_contextToIndex.TryGetValue(lower, out var index))
        {
            index = _styles.Count;
            _styles.Add(style);
            _contextToIndex.Add(lower, index);
        }
        else
        {
            _styles[index] = style;
        }
    }


    #region IEnumerable

    public IEnumerator<Style> GetEnumerator()
    {
        return _styles.GetEnumerator();
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        return _styles.GetEnumerator();
    }

    #endregion
}


public class MetadataIdChangedEventArgs(string oldId, string newId) : EventArgs
{
    /// <summary>
    ///     修改前的Id
    /// </summary>
    public string OldId { get; } = oldId;

    /// <summary>
    ///     修改后的Id
    /// </summary>
    public string NewId { get; } = newId;
}

public abstract class MetadataLabeledObject : MetadataNamedObject, IMetadataLabeledObject
{
    private string _id;

    protected MetadataLabeledObject(IMetadataDocument document, ObjectType type, string name)
        : base(document, type, name)
    {
        _id = Guid.NewGuid().ToString();
        Label = new MetadataLabels(document);
        Templates = new Templates(document);
        Style = null;
        LabelStyle = null;
        Notes = new Notes(document, this);
    }

    public string Id
    {
        get => _id;

        internal set
        {
            var old = _id;
            _id = value;
            IdChanged?.Invoke(this, new MetadataIdChangedEventArgs(old, value));
        }
    }

    public IMetadataLabels Label { get; }

    public ITemplates Templates { get; }

    public INotes Notes { get; }

    public IStyles? Style { get; set; }

    public IStyles? LabelStyle { get; set; }

    public void SetProperty(string name, string value)
    {
        GetProperty(name).SetValue(value);
    }

    public void SetProperty(string name, int value)
    {
        GetProperty(name).SetValue(value);
    }

    public void SetProperty(string name, double value)
    {
        GetProperty(name).SetValue(value);
    }

    public void SetProperty(string name, bool value)
    {
        GetProperty(name).SetValue(value);
    }

    public void SetProperty(string name, IProperty property)
    {
        GetProperty(name).SetValue(property);
    }

    public void SetProperty(string name, IProperties properties)
    {
        GetProperty(name).SetValue(properties);
    }

    internal event EventHandler<MetadataIdChangedEventArgs>? IdChanged;

    private IProperty GetProperty(string name)
    {
        return Properties.Get(name, Document.Context);
    }
}